<script setup lang="ts">
import {type PropType, ref,h} from "vue";
import type {FormInstance, FormRules} from "element-plus";
import  {type ElFormItem,COMPONENT_MAP} from "./types";

const props = defineProps({
  rules:Object as PropType<FormRules<any>>,
  inline:{
    type: Boolean,
    default:false,
  },
  'label-position':{
    type: String as PropType<'left' | 'right' | 'top'>,
    default:'top',
  },
  'label-width':{
    type: [Number,String],
    default:'100px'
  },
  'label-suffix':{
    type: String,
    default:":"
  },
  size:{
    type: String as PropType<'' | 'large' | 'default' | 'small'>,
    default:'large'
  },
  'scroll-to-error':{
    type:Boolean,
    default:true
  },
  formItems:{
    type:Array as PropType<ElFormItem[]>,
    required:false
  },
  addFunction:{
    type:Function as PropType<(data:any)=>Promise<any|undefined>>,
  },
  updateFunction:{
    type:Function as PropType<(data:any)=>Promise<any|undefined>>,
  },
  beforeSave:{
    type:Function as PropType<(data:any)=>Promise<any|undefined>|any>,
    default:async (data:any)=>{
      return data
    }
  },
  title:{
    type:String,
    default:'编辑'
  }
});
const emits = defineEmits<{
  (e:'ok',res?:any):void
}>();
const show=ref(false)
const formData=ref<any>({})
const saveType=ref<'update'|'add'|undefined>()
const formIns=ref<FormInstance>()
const open=(t:'update'|'add',f?:any)=>{
  show.value=true
  saveType.value=t
  formIns.value?.resetFields()
  formData.value= f?{...f}:{}
}
const close=()=>{
  show.value=false
}
const save=async ()=>{
  const b = await formIns.value?.validate();
  const d=await props.beforeSave(formData.value);
  if(b&&formData.value&&saveType.value){
    if (saveType.value==='update'&&props.updateFunction){
      const res=await props.updateFunction(d);
      emits('ok',res)
      close()
    }
    if (saveType.value==='add'&&props.addFunction){
      const res=await props.addFunction(d);
      emits('ok',res)
      close()
    }
  }
}
const renderCom=(e:ElFormItem)=>{
  return e?.component?COMPONENT_MAP[e.component]:h('div')
}
defineExpose({
  open,
  close,
})
</script>

<template>
  <!-- 保证组件数据不会串 -->
  <el-dialog v-model="show" :show-close="false" :title="props.title" destroy-on-close>
    <el-form ref="formIns" :model="formData" v-bind="props" >
      <el-form-item v-for="e in props.formItems" v-bind="e" :key="e.prop">
        <template v-if="e.slot">
          <slot :name="e.slot" :formData="formData"></slot>
        </template>
        <template v-else-if="e.component">
          <component style="width: 100%" :is="renderCom(e)" v-model="formData[e.prop]" v-bind="e.props" :form="formData"/>
        </template>
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="close">取消</el-button>
      <el-button type="primary" @click="save">保存</el-button>
    </template>
  </el-dialog>
</template>

<style scoped lang="scss">

</style>
